#include "QProperty.h"
#include <QObject>
#include <QMetaProperty>
#include <QItemEditorFactory>

#include "private/QProperty_p.h"

using namespace QPE;

//! Standard constructor, takes a name and a parent property as argument
QProperty::QProperty(const QString& name, QVariant::Type type)
	: d_ptr(new QPropertyPrivate(name, type))
{

}

QProperty::QProperty(QPropertyPrivate *d)
	: d_ptr(d)
{
}


QProperty::~QProperty()
{
	setParent(NULL);

	while(!d_ptr->Children.isEmpty())
	{
		QProperty* tmpChild = d_ptr->Children.takeLast();
		delete tmpChild;
	}

	delete d_ptr;
}

QString QProperty::type() const
{
	return "string";
}

//! Get the data how it should be displayed
QVariant QProperty::data (int column, int role) const
{
	if(column == DPC_Name && Qt::DisplayRole == role)
		return QVariant(d_ptr->Name);
	else if(column == DPC_Data && (Qt::DisplayRole == role || Qt::EditRole == role))
		return d_ptr->VariantValue;
	else if(Qt::ToolTipRole == role)
		return QVariant(d_ptr->Description);
	else
		return QVariant();
}

bool QProperty::setData(const QVariant &data, int role)
{
	bool tmpResult = false;
	if(Qt::EditRole == role)
	{
		tmpResult = (d_ptr->VariantValue != data);
		setValue(data);
	}

	return tmpResult;
}

bool QProperty::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index, const QAbstractItemDelegate *delegate) const
{
	Q_UNUSED(painter);
	Q_UNUSED(option);
	Q_UNUSED(index);
	Q_UNUSED(delegate);

	return false;
}

//! Returns an editor widget, or NULL if it doesn't supply one
QWidget* QProperty::createEditor(QWidget * parent, const QStyleOptionViewItem& options, const QAbstractItemDelegate* delegate)
{
	Q_UNUSED(options);
	Q_UNUSED(delegate);

	const QItemEditorFactory* tmpFactory = QItemEditorFactory::defaultFactory();
	return tmpFactory->createEditor(d_ptr->PropertyVariantType, parent);
}

bool QProperty::setEditorData(QWidget* editor)
{
	if(!editor)
		return false;

	QByteArray n = editor->metaObject()->userProperty().name();

	if (!n.isEmpty()) {
		editor->setProperty(n, d_ptr->VariantValue);
		return true;
	}

	return false;
}

//! Gets the data from the widget
QVariant QProperty::getEditorData(QWidget* editor) const
{
	if(!editor)
		return QVariant();

	QByteArray n = editor->metaObject()->userProperty().name();

	if (!n.isEmpty())
		return editor->property(n);
	else
		return QVariant();
}

//! Returns item flags
Qt::ItemFlags QProperty::flags(int column) const
{
	if(column == DPC_Name)
		return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
	else if(column == DPC_Data)
		return Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable;
	else
		return Qt::NoItemFlags;
}


void QProperty::setValue(const QVariant &value)
{
	d_ptr->VariantValue = value;
	d_ptr->VariantValue.convert(d_ptr->PropertyVariantType);
}


QVariant QProperty::getValue() const
{
	return d_ptr->VariantValue;
}

QString QProperty::serialize() const
{
	return getValue().toString();
}

void QProperty::deserialize(const QString& value)
{
	setValue(QVariant(value));
}


void QProperty::setName(const QString& name)
{
	d_ptr->Name = name;
}


QString QProperty::getName() const
{
	return d_ptr->Name;
}


void QProperty::setDescription(const QString& desc)
{
	d_ptr->Description = desc;
}


QString QProperty::getDescription() const
{
	return d_ptr->Description;
}




//! Returns a reference to the list of children
QList<QProperty*>& QProperty::getChildren()
{
	return d_ptr->Children;
}

//! Returns a reference to the list of children
const QList<QProperty*>& QProperty::getChildren() const
{
	return d_ptr->Children;
}

//! Returns the child at a certain row
QProperty* QProperty::getChild(int row) const
{
	if(row >= 0 && row < getRowCount())
		return d_ptr->Children.at(row);
	else
		return NULL;
}

//! Gets the number of children
int QProperty::getRowCount() const
{
   return d_ptr->Children.count();
}

//! Gets the parent of this property
QProperty* QProperty::getParent() const
{
	return d_ptr->Parent;
}

//! Sets the parent of this property
void QProperty::setParent(QProperty* parent)
{
	if(d_ptr->Parent == parent)
		return;

	QProperty* oldParent = d_ptr->Parent;
	d_ptr->Parent = parent;

	if(oldParent)
		oldParent->removeChild(this);

	if(d_ptr->Parent && d_ptr->Parent->getChildRow(this) == -1)
		d_ptr->Parent->addChild(this);
}

int QProperty::addChild(QProperty *child)
{
	if(child && child->getParent() != this)
		child->setParent(this);

	if(!d_ptr->Children.contains(child) && child != NULL)
	{
		d_ptr->Children.push_back(child);
		return d_ptr->Children.count()-1;
	}
	else
	{
		return d_ptr->Children.indexOf(child);
	}
}

//! Removes a child from the children list
void QProperty::removeChild(QProperty* child)
{
	d_ptr->Children.removeAll(child);

	if(child && child->getParent() == this)
		child->setParent(NULL);
}

//! Returns the row the child has
int QProperty::getChildRow(QProperty* child) const
{
	return d_ptr->Children.indexOf(child);
}


//! Returns whether the views have to update the parent of this property if it changes
bool QProperty::getUpdateParent() const
{
	return d_ptr->UpdateParent;
}

//! Returns whether the views have to update the children of this property if it changes
bool QProperty::getUpdateChildren() const
{
	return d_ptr->UpdateChildren;
}

//! Sets whether the views should update Parents or children after this property changes
void QProperty::setUpdateBehaviour(bool update_parent, bool update_children)
{
	d_ptr->UpdateParent = update_parent;
	d_ptr->UpdateChildren = update_children;
}


void QProperty::setSettings(const QMap<QString, QVariant>& settings)
{
	QMap<QString, QVariant>::const_iterator tmpIterator = settings.constBegin();
	for (; tmpIterator != settings.constEnd(); ++tmpIterator) {
		setSetting(tmpIterator.key(), tmpIterator.value());
	}
}

QMap<QString, QVariant> QProperty::getSettings() const
{
	QMap<QString, QVariant> tmpResult;

	QStringList tmpKeyList = getSettingKeys();
	foreach(const QString& tmpKey, tmpKeyList)
		tmpResult.insert(tmpKey, getSetting(tmpKey));

	return tmpResult;
}

void QProperty::setSetting(const QString& key, const QVariant& value)
{
	Q_UNUSED(key)
	Q_UNUSED(value)
	// Not needed in the Standard property
}

QVariant QProperty::getSetting(const QString& key) const
{
	// Not needed in the Standard property
	Q_UNUSED(key)
	return QVariant();
}

QStringList QProperty::getSettingKeys() const
{
	return QStringList();
}

QProperty* QProperty::clone(bool include_children, QProperty* container) const
{
	if(!container)
		container = new QProperty(getName(), d_ptr->PropertyVariantType);

	container->setName(getName());
	container->setDescription(getDescription());
	container->setValue(getValue());
	container->setSettings(getSettings());
	container->setUpdateBehaviour(getUpdateParent(), getUpdateChildren());

	if(include_children) {
		foreach(QProperty* tmpChild, d_ptr->Children)
			container->addChild(tmpChild->clone(true));
	}

	return container;
}
